// ------------------------------------------------------------------------------------
// REVISION LOG ENTRY
// Revision By: (C) Copyright 2014 Hiroyuki Tominaga, All Rights Reserved.
//
//  Revised on : 2014-06-22 13:46:10
//  Summary    : Tkit Action  class.
//  require :
//        jQuery 1.8 over
//        https://js-extension-afx.googlecode.com/svn/trunk/jsafx.js
//        https://js-dragwindow.googlecode.com/svn/trunk/tkit.js
// ------------------------------------------------------------------------------------

/**
 * class Tkit.Action
 */
(function(name_space)
{    /* Strict mode for this plugin */
    "use strict";

    var _DEBUG = false;
    var tkit; {
        var W = (window || self);
        W.$ = W.$ || {};
        /* */
        tkit = W[name_space];
        (!tkit) && ( tkit = W[name_space] = {} );
        if (!W.$.noop) {
            W.$.noop = function(){};
        }
    }

    // context menu evnet names.
    var CM_CANCEL_EVENT = "mousedown.tkit-contextmenu";
    var CM_EVENT = "contextmenu.tkit-contextmenu";

    var CM_ACTION_EVENT = "mousedown.tkit-action";
    var CM_FADE_TIME = 300;
    var DUMMY_CSS = {
        position: "absolute",
        top: "-1000px", left: "-1000px",
        display: "block", "z-Index": 100 /* important z-Index */
    };

    var Action;
    /**
     * class Tkit.Action
     */
    tkit.Action = function Action(e, map) {
        /*tkit.initAtom(
            this, tkit.Action, tkit.XWidget, arguments
        );*/
        tkit.extendBase(this, tkit.Action, arguments);
        this.commands = {};
        this.reference = {};
        if (map !== null && typeof map === "object")
            this.addReference(map);
    };
    Action = tkit.Action;
    Action.qname = name_space + ".Action";

    Action.prototype =
    {
        // super class の install は parameter なしだが, ここでは
        // json object を指定可能.
        // 省略した場合は, default の設定で初期化される.
        install: function (json_obj) {
            this.updateOptions(json_obj);
        },
        /**
         * json format for this class:
         * "&lt;element id>": {
         *     "items": [
         *    ["&lt;Action name>", "&lt;inner html tag>"],
         *       ...
         *   ]
         * }
         *
         * &lt;Action name> equals "data-action" attribute.(&lt;li data-action="&lt;Action name>">&lt;/li>
         */
        updateOptions: function updateOptions(json_obj) {
            var cfg = $.isPlainObject(json_obj)? json_obj[this._e.id]: null;
            var jqo, _action = this;
            var css_m_out , css_m_over;

            var is_object = $.isPlainObject(cfg);
            if (is_object) {
                (cfg.mouseout) && (css_m_out = cfg.mouseout), (cfg.mouseover) && (css_m_over = cfg.mouseover);
                cfg.fadetime && ( this.fade_t = parseInt(cfg.fadetime) ); // number or string
            } else {
                css_m_out = { "border":"solid 1px rgba(192, 192, 192, 0)", "border-radius": "3px" };
                css_m_over = { "border":"solid 1px rgba(192, 192, 192, 1)" };
            }

            // not a click, must mousedown event.
            (jqo = this.$()).find("[data-action]").on(CM_ACTION_EVENT, function (e) {
                _action.perform(this.getAttribute("data-action"), e);
            }).on("mouseover.tkit-menuitem", function(e) {
                $(this).css(css_m_over);
            }).on("mouseout.tkit-menuitem", function(e) {
                $(this).css(css_m_out);
            }).css(css_m_out);

            if (is_object && cfg.items) { // innerHTML を json に記述している場合.
                ("forEach" in cfg.items) && (
                    cfg.items.forEach(function(value, index, arry) {
                        jqo.find("[data-action=" + value[0] + "]").html(value[1]);
                    })
                );
            }
            //console.log( jqo.children(":first").outerWidth() );
            // display: none の場合は 0 が返されるが,
            // display: block で表示するとき, child element の width で表示される.
            // 幅の取得をしないと window 領域に収めることが出来ない.
            // 仕方がないので, user に見えない領域で表示させることで width 取得を可能にする.
            jqo.css( DUMMY_CSS )
            .css("width", jqo.children(":first").outerWidth() + "px");
            //.css("display", "none");
        },
        release: function () {
            this.$().find("[data-action]")
            .unbind(CM_ACTION_EVENT)
            .unbind("mouseover.tkit-menuitem")
            .unbind("mouseout.tkit-menuitem");
            return this;
        },

        fade_t: CM_FADE_TIME,

        cm_target: null,
        enableContextMenu: true,
        toggleMenuEnable: function () {
            return (this.enableContextMenu = !this.enableContextMenu);
        },

        /**
         * can be override.
         */
        showMenu: function(e, jqo) {
			jqo.fadeIn(this.fade_t);
        },
        /**
         * can be override.
         */
        hideMenu: function(e, jqo) {
            if (e.button == 2)
                jqo.css("display", "none");
            else
                jqo.fadeOut(this.fade_t);
        },

        /**
         * selector を指定しない場合, document となる.
         * 再度, contextMenuOn() を call すると, context menu の target を変更可能.
         */
        contextMenuOn: function (selector) {
            selector === undefined && (selector = document);
            var _this = this;
            // context menu の target を任意に変更可能.
            if (this.cm_target !== null) {
                $(document).unbind(CM_CANCEL_EVENT);
                this.cm_target.unbind(CM_EVENT);
            }
            //
            this.cm_target = $(selector).on(CM_EVENT, contextMenu);
            function contextMenu(e) {
                if (!_this.enableContextMenu)
                    return;
                if (e.button == 2) {
                    var jqo = _this.$();
                    _this.showMenu(
                    	e, jqo.css( $.confineToWindow(jqo, e, "none") )
                    );//.fadeIn(_this.fade_t);
                    e.preventDefault(), e.stopImmediatePropagation();
                }
                $(document).on(CM_CANCEL_EVENT, hideMenu);
                _this.cm_target.unbind(CM_EVENT);
                return false;
            }
            function hideMenu(e) {
                /*var jqo = _this.$();
                if (e.button == 2)
                    jqo.css("display", "none");
                else
                    jqo.fadeOut(_this.fade_t);*/
                _this.hideMenu( e, _this.$() );
                _this.cm_target.on(CM_EVENT, contextMenu);
                $(document).unbind(CM_CANCEL_EVENT);
            }
        },
        /**
         * set the objects that reference at execute.
         */
        addReference: function (map) {
            $.extend(this.reference, map);
            return this;
        },
        /**
         * register  function.（Dynamic binding
         */
        add: function(actionName, handler) {
            this.commands[actionName] = handler;
            return this;
        },
        /**
         * execute registered functions.
         */
        fire: function(actionName/*, args*/) {
            var fn = this.commands[actionName];
            typeof fn === "function" && (
                fn.apply(this.reference, Array.prototype.slice.call(arguments, 1))
            );
        },
        /**
         * MUST override.
         *
         * action.perform = function(actionName, arg0, arg1, arg2, arg3) {
         *     var sval;
         *     with(this.reference) { // NG in strict mode.
         *         switch(actionName) {
         *            case "FILE": sval = doc.body.tagName; break;
         *            case "SAVE": case "SAVED": case "IMPORT":
         *                sval = actionName + ": " + arg0.data; break;
         *        }
         *        $("#text").text(sval);
         *    }
         * };
         */
        perform: $.noop
    };

})("Tkit");    // (function()


